<template>
	<div>JavaScript 中如何实现并发控制？</div>
	<div>asyncPool ES7 实现</div>
	<div>https://github.com/rxaviers/async-pool/</div>
</template>

<script>
	import {
		ref,
		reactive
	} from 'vue'
	export default {
		data() {
			return {
				title:'实现并发控制+手写Promise.all+手写Promise.race'
			}
		},
		mounted() {
			this.asyncPool7Test();
			this.testPromiseAll();
			this.asyncPool6Test();

		},
		methods: {
			async asyncPool7(poolLimit, array, iteratorFn) {
				const ret = []; // 存储所有的异步任务
				const executing = []; // 存储正在执行的异步任务
				for (const item of array) {
					// 调用iteratorFn函数创建异步任务
					const p = Promise.resolve().then(() => iteratorFn(item, array));
					ret.push(p); // 保存新的异步任务

					// 当poolLimit值小于或等于总任务个数时，进行并发控制
					if (poolLimit <= array.length) {
						// 当任务完成后，从正在执行的任务数组中移除已完成的任务
						const e = p.then(() => executing.splice(executing.indexOf(e), 1));
						executing.push(e); // 保存正在执行的异步任务
						if (executing.length >= poolLimit) {
							await Promise.race(executing); // ！！！等待较快的任务执行完成
						}
					}
				}
				return Promise.all(ret);
			},
			async asyncPool7Test() {
				var timeout = i => new Promise(resolve => setTimeout(() => {
					console.log('asyncPool7Test='+ i + 'finishes')
					resolve(i)
				}, i))
				var result = await this.asyncPool7(2, [1000, 5000, 3000, 2000], timeout)
				// Call iterator (i = 1000)
				// Call iterator (i = 5000)
				// Pool limit of 2 reached, wait for the quicker one to complete...
				// 1000 finishes
				// Call iterator (i = 3000)
				// Pool limit of 2 reached, wait for the quicker one to complete...
				// 3000 finishes
				console.log('执行到此处的时候，时间已经花了4000=1000+3000，执行5000只需要5000-4000=1000，而新加入的任务需要2000，故race先执行5000')
				// Call iterator (i = 2000)
				// Itaration is complete, wait until running ones complete...
				// 5000 finishes
				// 2000 finishes
				console.log('result', result)
			},

			async testPromiseAll() {
				var timeout = i => new Promise(resolve => setTimeout(() => {
					console.log('===testPromiseAll===' + i + 'finishes')
					resolve(i)
				}, i))
				var result = await Promise.all([timeout(1000), timeout(5000), timeout(3000), timeout(2000)])
				console.log('testPromiseAll=result', result)
			},

			async asyncPool6(poolLimit, array, iteratorFn) {
				let i = 0;
				const ret = []; // 存储所有的异步任务
				const executing = []; // 存储正在执行的异步任务
				const enqueue = function() {
					if (i === array.length) {
						return Promise.resolve();
					}
					const item = array[i++]; // 获取新的任务项
					const p = Promise.resolve().then(() => iteratorFn(item, array));
					ret.push(p);

					let r = Promise.resolve();

					// 当poolLimit值小于或等于总任务个数时，进行并发控制
					if (poolLimit <= array.length) {
						// 当任务完成后，从正在执行的任务数组中移除已完成的任务
						const e = p.then(() => executing.splice(executing.indexOf(e), 1));
						executing.push(e);
						if (executing.length >= poolLimit) {
							r = Promise.race(executing);
						}
					}

					// 正在执行任务列表 中较快的任务执行完成之后，才会从array数组中获取新的待办任务
					return r.then(() => enqueue());
				};
				return enqueue().then(() => Promise.all(ret));
			},

			async asyncPool6Test() {
				var timeout = i => new Promise(resolve => setTimeout(() => {
					console.log('===asyncPool6Test===' + i + 'finishes')
					resolve(i)
				}, i))
				//1200finishes,3500finishes,3000finishes
				var result = await this.asyncPool6(2, [1200, 3500, 3000, 2000], timeout)
				console.log('asyncPool6Test=result=', result)
			},

			async testPromiseAll2() {
				console.log('=============testPromiseAll2')
				var result = await Promise.all([1, Promise.resolve(2)])
				console.log('result', result) //result  [1, 2]
				var result = await Promise.all([1, Promise.reject(2)])
					.catch(e => console.log(e, '<- Error')) // 2 "<- Error"
				var result = await Promise.all([1, Promise.resolve(2), 3])
				console.log('result', result) //result  [1, 2 ,3]
			},
			//手写一个 Promise.all,大概就是维护一个数组，把所有 promise 给 resolve 了之后都扔进去
			pAll(_promises) {
				return new Promise((resolve, reject) => {
					// Iterable => Array
					const promises = Array.from(_promises)
					// 结果用一个数组维护
					const r = []
					const len = promises.length
					let count = 0
					for (let i = 0; i < len; i++) {
						// Promise.resolve 确保把所有数据都转化为 Promise
						Promise.resolve(promises[i]).then(o => {
							// 因为 promise 是异步的，保持数组一一对应
							r[i] = o;

							// 如果数组中所有 promise 都完成，则返回结果数组
							if (++count == len) {
								resolve(r)
							}
							// 当发生异常时，直接 reject
						}).catch(e => reject(e))
					}
				})
			},

			//手写一个 Promise.all,大概就是维护一个数组，把所有 promise 给 resolve 了之后都扔进去
			promise2All(iterators) {
				return new Promise((resolve, reject) => {
					if (!iterators || iterators.length === 0) {
						resolve([]);
					} else {
						let count = 0; // 计数器，用于判断所有任务是否执行完成
						let result = []; // 结果数组
						for (let i = 0; i < iterators.length; i++) {
							// 考虑到iterators[i]可能是普通对象，则统一包装为Promise对象
							Promise.resolve(iterators[i]).then(
								(data) => {
									result[i] = data; // 按顺序保存对应的结果
									// 当所有任务都执行完成后，再统一返回结果
									if (++count === iterators.length) {
										resolve(result);
									}
								},
								(err) => {
									reject(err); // 任何一个Promise对象执行失败，则调用reject()方法
									return;
								}
							);
						}
					}
				})
			},
			
			//手写一个 Promise.race,循环迭代promise任务，同步执行，只返回最新执行的resolved 或 rejected对象
			promise2Race(iterators) {
				return new Promise((resolve, reject) => {
					if (!iterators || iterators.length === 0) {
						resolve([]);
					} else {
						let count = 0; // 计数器，用于判断所有任务是否执行完成
						let result = []; // 结果数组
						for (let i = 0; i < iterators.length; i++) {
							// 考虑到iterators[i]可能是普通对象，则统一包装为Promise对象
							Promise.resolve(iterators[i]).then(
								(data) => {
										resolve(data);
								},
								(err) => {
									reject(err); // 任何一个Promise对象执行失败，则调用reject()方法
									return;
								}
							);
						}
					}
				})
			},

		},
	}
</script>

<style>
</style>
